Pino 简介
Pino 是 Node.js 生态中性能最高的日志库之一,官方定位为 "very low overhead Node.js logger"。基准测试显示其吞吐量约为 Winston 的 2-5 倍,且默认输出结构化 JSON,与现代可观测性栈(ELK、Loki、Datadog)天然契合。
安装与集成
pnpm add nestjs-pino pino pino-pretty
bash
在模块中注册 LoggerModule:
// app.module.ts
import { LoggerModule } from 'nestjs-pino';
@Module({
imports: [
LoggerModule.forRoot({
pinoHttp: {
level: 'info',
transport: process.env.NODE_ENV !== 'production'
? { target: 'pino-pretty', options: { colorize: true } }
: { target: 'pino-roll', options: { file: 'logs/log.txt', frequency: 'daily', mkdir: true } },
},
}),
],
})
export class AppModule {}
typescript
在 Controller 中使用
import { Controller, Get } from '@nestjs/common';
import { PinoLogger } from 'nestjs-pino';
@Controller('users')
export class UserController {
constructor(private readonly logger: PinoLogger) {}
@Get()
findAll() {
this.logger.info('Request GET /users succeeded');
return { data: [] };
}
}
typescript
nestjs-pino 的核心优势:自动记录所有 HTTP 请求和响应,无需手动编写请求日志。每次请求会自动输出请求方法、路径、Cookie、响应数据和耗时。
开发环境:pino-pretty 格式化
默认 JSON 输出在终端中不易阅读,pino-pretty 提供彩色格式化:
# 安装
pnpm add -D pino-pretty
bash
配置后,日志从:
{"level":30,"time":1716123456789,"msg":"Request GET /users succeeded"}
json
变为彩色可读格式,包含时间戳、请求路径、响应状态码、耗时等。
仅开发环境启用,生产环境不需要。
生产环境:pino-roll 日志滚动
pino-roll 是 Pino 的日志文件滚动传输插件,支持按时间或大小自动切割日志文件:
pnpm add pino-roll
bash
transport: {
target: 'pino-roll',
options: {
file: path.join('logs', 'log.txt'), // 日志文件路径
frequency: 'daily', // 按天滚动,可选 'hourly'
size: '10m', // 或按大小滚动,如 '10m' = 10MB
mkdir: true, // 自动创建目录
},
}
typescript
| 配置项 | 说明 | 示例 |
|---|---|---|
file | 日志文件路径 | path.join('logs', 'app.log') |
frequency | 滚动周期 | 'daily'、'hourly' |
size | 按大小滚动(与 frequency 二选一) | '10m'、'100k' |
mkdir | 自动创建目录 | true |
环境自适应配置
将开发与生产配置合并为条件判断:
// app.module.ts
import { LoggerModule } from 'nestjs-pino';
import * as path from 'path';
@Module({
imports: [
LoggerModule.forRoot({
pinoHttp: {
level: process.env.NODE_ENV === 'production' ? 'warn' : 'debug',
transport: process.env.NODE_ENV !== 'production'
? { target: 'pino-pretty', options: { colorize: true } }
: {
targets: [
{ target: 'pino-roll', level: 'info', options: { file: path.join('logs', 'app.log'), frequency: 'daily', mkdir: true } },
],
},
},
}),
],
})
export class AppModule {}
typescript
全局注册后,所有模块的请求都会被自动记录。建议在 AppModule 而非具体业务模块中注册,确保全局生效。
PinoLogger.assign() — 请求上下文绑定
nestjs-pino 提供的 PinoLogger 支持通过 assign() 自动在后续日志中附加上下文数据:
@Controller('orders')
export class OrderController {
constructor(private readonly logger: PinoLogger) {}
@Post()
create(@Body() body: { userId: string }) {
this.logger.assign({ userId: body.userId });
this.logger.info('Creating order'); // 自动包含 userId
}
}
typescript
这利用了 Node.js 的 AsyncLocalStorage,在请求生命周期内自动传播上下文,无需手动传递 request 对象。
↑